"""
This file provides basic operations support on Google Storage.
Currently, upload/download/delete operations are supported.
"""

import os, sys
import tempfile
import hashlib

sys.path.append('./boto')
import boto
from env import *
from boto.exception import GSResponseError
from boto.exception import InvalidUriError

"Get your developer keys from the .boto config file."
config = boto.config


def upload_file(fullname, dst_name):
  """
  This function upload file to Google Storage bucket: ollir-cp.
  @example
    fullname: /tmp/dir/a.txt
    dst_name: dir/a.txt
  """

  "Create source and destination URIs."
  src_uri = boto.storage_uri(fullname, "file")
  dst_uri = boto.storage_uri(bucket_name, "gs")

  "Create a new destination URI with the source file name as the object name."
  new_dst_uri = dst_uri.clone_replace_name(dst_name)

  "Create a new destination key object."
  dst_key = new_dst_uri.new_key()
    
  "Retrieve the source key and create a source key object."
  src_key = src_uri.get_key()
          
  "Create a temporary file to hold your copy operation."
  tmp = tempfile.TemporaryFile()
  src_key.get_file(tmp)
  tmp.seek(0)

  "Upload the file."
  dst_key.set_contents_from_file(tmp)

def ls_remote_file(email_address):
  filedir=[]
  dst_uri = boto.storage_uri(bucket_name, "gs")
  "objs = dst_uri.get_bucket()"

  for obj in dst_uri.get_all_keys():
    entry_list = obj.get_acl().entries.entry_list
    for entry in entry_list:
      if email_address == entry.scope.email_address and entry.permission in file_permissions:
        "print obj.name"
        filedir.append(obj.name)
        break
  return filedir

def _get_md5(file):
  f = open(file).read()
  m = hashlib.md5()
  m.update(f)
  return m.hexdigest()

def compare_file_meta(dst_name):
  """
  This function compare the local file and remote file, return one of the following status:
  ['local_not_exists', 'remote_not_exists', 'synced', 'local_newer', 'remote_newer']
  """
  local_file = os.path.join(local_dir, dst_name)
  if not os.path.exists(local_file):
    return 'local_not_exists'
    
  try:
    dst_uri = boto.storage_uri(bucket_name, "gs")
    new_dst_uri = dst_uri.clone_replace_name(dst_name)
    file_key = new_dst_uri.get_key()
  except InvalidUriError:
    return 'remote_not_exists'

  local_md5 = _get_md5(local_file)
  remote_md5 = file_key.etag.strip('"\'')
  if local_md5 == remote_md5:
    return 'synced'

def set_access_permission(dst_name, email_address, permission="FULL_CONTROL"):
  """
  This function set the file permission.
  """

  dst_uri = boto.storage_uri(bucket_name, "gs")
  new_dst_uri = dst_uri.clone_replace_name(dst_name)

  if permission in file_permissions:
    new_dst_uri.add_email_grant(permission, email_address)

def download_file(src_file, dst_path):
  """
  This function download file from GS, and put it to dest_path.
  @example
    src_file: dir/a.txt
    dst_path: /tmp
    => /tmp/dir/a.txt
  """

  "Download the files."
  src_uri = boto.storage_uri(bucket_name + "/" + src_file, "gs")
  dst_uri = boto.storage_uri(dst_path, "file")
  
  "Append the object name to the directory name."
  dst_key_name = dst_uri.object_name + os.sep + src_uri.object_name
  
  "Use the new destination key name to create a new destination URI."
  new_dst_uri = dst_uri.clone_replace_name(dst_key_name)
  
  "Create a new destination key object."
  dst_key = new_dst_uri.new_key()
  
  "Retrieve the source key and create a source key object."
  src_key = src_uri.get_key()
  
  "Create a temporary file to hold our copy operation."
  tmp = tempfile.TemporaryFile()
  src_key.get_file(tmp)
  tmp.seek(0)
  
  "Download the object."
  dst_key.set_contents_from_file(tmp)

def delete_file(src_file):
  """
  This function delete a file.
  """

  "Create a URI for a bucket."
  uri = boto.storage_uri(bucket_name, "gs")

  "Get the objects that are in the bucket."
  objs = uri.get_bucket()

  "Delete the objects first, then the bucket."
  if objs:
    for obj in objs:
      if obj.name == src_file:
        obj.delete()


if __name__ == '__main__':
  if sys.argv[1] == 'upload':
    file_names = sys.argv[2:]
    for fullname in file_names:
      basename = os.path.basename(os.path.abspath(fullname))
      upload_file(fullname, basename)
      set_access_permission(basename, email_address, "FULL_CONTROL")

  elif sys.argv[1] == 'download':
    file_names = sys.argv[2:-1]
    dst_path = sys.argv[-1]
    for file in file_names:
      download_file(file, dst_path)

  elif sys.argv[1] == 'ls':
    ls_remote_file(email_address)

  elif sys.argv[1] == 'delete':
    file_names = sys.argv[2:]
    for file in file_names:
      delete_file(file)

  elif sys.argv[1] == 'check':
    file_names = sys.argv[2:]
    for file in file_names:
      print compare_file_meta(file)
